/*
* ============================================================================
*  Name     : HttpModule.cpp
*  Part of  : GV60
*  Copyright: Wipo Software
* ============================================================================
*/

#include <uri8.h>
#include <http.h>
#include <chttpformencoder.h>
#include <HttpStringConstants.h>
#include <http\RHTTPTransaction.h>
#include <http\RHTTPSession.h>
#include <http\RHTTPHeaders.h>
#include <stringpool.h>
#include <es_sock.h>
#include <commdb.h>

#include <avkon.hrh>
#include <commdbconnpref.h>
#include <aknnotewrappers.h>

#include "HttpModule.h"
#include "Logger.h"


#define HTTP_BODY_CHUNK        8000
#define MAX_HTTP_ATTEMPTS         5

// Used user agent for requests
_LIT8(KUserAgent, "Wipo 1.0");

// This client accepts all content types.
_LIT8(KAccept, "*/*");

// Empty string
_LIT8(KEmptyString, "");

CHttpCollection::CHttpCollection()
{
  for (TInt i = 0; i < MAX_HTTP_COUNT; i++)
  {
    m_pName[i]  = NULL;
    m_pValue[i] = NULL;
  }
  m_iCount = 0;
}

CHttpCollection::~CHttpCollection()
{
  Reset();
}

void CHttpCollection::Reset()
{
  for (TInt i = 0; i < MAX_HTTP_COUNT; i++)
  {
    if (m_pName[i])
    {
      delete m_pName[i];
      m_pName[i] = NULL;
    }
    if (m_pValue[i])
    {
      delete m_pValue[i];
      m_pValue[i] = NULL;
    }
  }
  m_iCount = 0;
}

void CHttpCollection::Remove(const TDesC8& iName)
{
  for (TInt i = 0; i < m_iCount; i++)
  {
    if (m_pName[i]->Compare(iName) == 0)
    {
      delete m_pName[i];
      m_pName[i] = NULL;
      
      delete m_pValue[i];
      m_pValue[i] = NULL;
      
      m_pName[i]  = m_pName[m_iCount - 1];
      m_pValue[i] = m_pValue[m_iCount - 1];
      m_iCount--;
      
      return;
    }
  }
}

void CHttpCollection::Set(const TDesC8& iName, const TDesC8& iValue)
{
  Remove(iName);

  if (m_iCount < MAX_HTTP_COUNT)
  {
    m_pName[m_iCount] = iName.Alloc();
    m_pValue[m_iCount] = iValue.Alloc();
    if (m_pName[m_iCount] && m_pValue[m_iCount])
    {
      m_iCount++;
    }
  }
}

const TDesC8& CHttpCollection::Get(const TDesC8& iName)
{
  for (TInt i = 0; i < m_iCount; i++)
  {
    if (m_pName[i]->Compare(iName) == 0)
    {
      return *m_pValue[i];
    }
  }
  return KEmptyString;
}

const TDesC8& CHttpCollection::GetName(TInt iCount)
{
  if (iCount < m_iCount)
  {
    return *m_pName[iCount];
  }
  return KEmptyString;
}

const TDesC8& CHttpCollection::GetValue(TInt iCount)
{
  if (iCount < m_iCount)
  {
    return *m_pValue[iCount];
  }
  return KEmptyString;
}

CHttpModule* CHttpModule::NewL(MHttpModuleObserver* n_pObserver, TUint32 n_iap)
{
  CHttpModule* self = CHttpModule::NewLC(n_pObserver, n_iap);
  CleanupStack::Pop(self);
  return self;
}

CHttpModule* CHttpModule::NewLC(MHttpModuleObserver* n_pObserver, TUint32 n_iap)
{
  CHttpModule* self = new (ELeave) CHttpModule();
  CleanupStack::PushL(self);
  self->ConstructL(n_pObserver, n_iap);
  return self;
}

CHttpModule::CHttpModule() :
  CActive(EPriorityStandard)
{
  m_bRunning          = EFalse;
  m_pPostData         = NULL;
  m_pResponseBody     = NULL;
  m_pHeaderCollection = NULL;
  m_pObserver         = NULL;
  m_pUsername         = NULL;
  m_pPassword         = NULL;
  m_pHttpTimer        = NULL;
  m_iStatusCode       = 0;
  
  CActiveScheduler::Add(this);
}

CHttpModule::~CHttpModule()
{
  // Cancel transaction, if still pending
  StopTransaction();
  
  m_iSession.Close();
  m_iConnection.Close();
  m_iSockServ.Close(); 

  if (m_pPostData)
  {
    delete m_pPostData;
    m_pPostData = NULL;
  }
  if (m_pResponseBody)
  {
    delete m_pResponseBody;
    m_pResponseBody = NULL;
  }
  if (m_pUsername)
  {
    delete m_pUsername;
    m_pUsername = NULL;
  }
  if (m_pPassword)
  {
    delete m_pPassword;
    m_pPassword = NULL;
  }
  if (m_pHttpTimer)
  {
    StopTimer();
    delete m_pHttpTimer;
    m_pHttpTimer = NULL;
  }

  // Cancel and deque active object
  if (IsActive())
  {
    Cancel();
  }
  Deque();
}

void CHttpModule::ConstructL(MHttpModuleObserver* n_pObserver, TUint32 n_iap)
{
  // Open RHTTPSession with default protocol ("HTTP/TCP")
  m_iSession.OpenL();

  // Install this class as the callback for authentication requests. When 
  // page requires authentication the framework calls GetCredentialsL to get 
  // user name and password.
  InstallAuthenticationL(m_iSession);

  // Connection to given IAP
  if (n_iap != 0)
  {
    TCommDbConnPref pref;
    pref.SetIapId(n_iap); // IAP ID for connection to be used
    pref.SetDialogPreference( ECommDbDialogPrefDoNotPrompt );
    pref.SetDirection( ECommDbConnectionDirectionOutgoing );
  
    m_iSockServ.Connect();
    m_iConnection.Open(m_iSockServ);
    m_iConnection.Start(pref);
  }
  else
  {
    m_iSockServ.Connect();
    m_iConnection.Open(m_iSockServ);
    m_iConnection.Start();
  }

  RStringPool iStringPool = m_iSession.StringPool();
  RHTTPConnectionInfo connInfo = m_iSession.ConnectionInfo();
  connInfo.SetPropertyL ( iStringPool.StringF(HTTP::EHttpSocketServ, RHTTPSession::GetTable() ), THTTPHdrVal (m_iSockServ.Handle()) );
  TInt connPtr = REINTERPRET_CAST(TInt, &m_iConnection);
  connInfo.SetPropertyL ( iStringPool.StringF(HTTP::EHttpSocketConnection, RHTTPSession::GetTable() ), THTTPHdrVal (connPtr) );

  // Save pointer of callback function and userdata
  m_pObserver = n_pObserver;
}

void CHttpModule::SetHeaderL(RHTTPHeaders aHeaders, TInt aHdrField, const TDesC8& aHdrValue)
{
  RStringF valStr = m_iSession.StringPool().OpenFStringL(aHdrValue);
  CleanupClosePushL(valStr);
  THTTPHdrVal val(valStr);
  aHeaders.SetFieldL(m_iSession.StringPool().StringF(aHdrField, RHTTPSession::GetTable()), val);
  CleanupStack::PopAndDestroy(); // valStr
}

void CHttpModule::SetCookiesL(RHTTPHeaders aHeaders)
{
  RStringF cookieField = m_iSession.StringPool().StringF(HTTP::ECookie, RHTTPSession::GetTable());
  CleanupClosePushL(cookieField);
  
  TBuf8<300> tempBuff;
  for (TInt i = 0; i < m_iCookieArray.Count(); i++)
  {
    tempBuff.Append(m_iCookieArray.GetName(i));
    tempBuff.Append(_L8("="));
    tempBuff.Append(m_iCookieArray.GetValue(i));
    tempBuff.Append(_L8("; "));
  }

  aHeaders.SetRawFieldL(cookieField, (const TDesC8&)tempBuff, _L8(";"));
  CleanupStack::PopAndDestroy(); // cookieField
}

void CHttpModule::SetAuthentication(const TDesC8& aUsername, const TDesC8& aPassword)
{
  if (m_pUsername)
  {
    delete m_pUsername;
    m_pUsername = NULL;
  }
  m_pUsername = aUsername.Alloc();

  if (m_pPassword)
  {
    delete m_pPassword;
    m_pPassword = NULL;
  }
  m_pPassword = aPassword.Alloc();
}

TInt CHttpModule::IssueHTTPGetL(const TDesC8& aUri, TInt iMaxTimer, CHttpHeaderCollection* pHeaders)
{
  // Ignore more requests if already running
  if (m_bRunning)
  {
    return KErrInUse;
  }

  // Parse string to URI (as defined in RFC2396)
  TUriParser8 uri;
  if (KErrNone != uri.Parse(aUri))
  {
    return KErrArgument;
  }

  DEBUG2("HTTP GET request: ", aUri);
  
  m_pHeaderCollection = pHeaders;
  
  // Get request method string for HTTP GET
  RStringF method = m_iSession.StringPool().StringF(HTTP::EGET, RHTTPSession::GetTable());

  // Open transaction with previous method and parsed uri. This class will
  // receive transaction events in MHFRunL and MHFRunError.
  m_iTransaction = m_iSession.OpenTransactionL(uri, *this, method);

  // Set headers for request; user agent and accepted content type
  RHTTPHeaders hdr = m_iTransaction.Request().GetHeaderCollection();
  SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent);
  SetHeaderL(hdr, HTTP::EAccept, KAccept);
  
  SetCookiesL(hdr);

  // Delete previous buffer and allocate a new buffer
  if (m_pResponseBody)
  {
    delete m_pResponseBody;
    m_pResponseBody = NULL;
  }
  m_pResponseBody = HBufC8::NewL(HTTP_BODY_CHUNK);
  m_iStatusCode = 0;
  
  // Submit the transaction. After this the framework will give transaction
  // events via MHFRunL and MHFRunError.
  m_iTransaction.SubmitL();

  m_bRunning = ETrue;
  m_iHttpAttempt = 0;
    
  // Start timer (if required)
  TRAP_IGNORE( StartTimerL(iMaxTimer) );
  
  return KErrNone;
}

TInt CHttpModule::IssueHTTPPostL(const TDesC8& aUri, const TDesC8& aContentType, const TDesC8& aBody, TInt iMaxTimer, CHttpHeaderCollection* pHeaders)
{
  // Ignore more requests if already running
  if (m_bRunning)
  {
    return KErrInUse;
  }

  // Parse string to URI
  TUriParser8 uri;
  if (KErrNone != uri.Parse(aUri))
  {
    return KErrArgument;
  }

  DEBUG2("HTTP POST request: ", aUri);
  
  m_pHeaderCollection = pHeaders;

  // Copy data to be posted into member variable; m_pPostData is used later in
  // methods inherited from MHTTPDataSupplier.
  if (m_pPostData)
  {
    delete m_pPostData;
    m_pPostData = NULL;
  }
  if (aBody.Length() > 0)
  {
    m_pPostData = aBody.AllocL();
  }

  // Get request method string for HTTP POST
  RStringF method = m_iSession.StringPool().StringF(HTTP::EPOST, RHTTPSession::GetTable());

  // Open transaction with previous method and parsed uri. This class will 
  // receive transaction events in MHFRunL and MHFRunError.
  m_iTransaction = m_iSession.OpenTransactionL(uri, *this, method);
  
  // Set headers for request; user agent, accepted content type and body's 
  // content type.
  RHTTPHeaders hdr = m_iTransaction.Request().GetHeaderCollection();
  SetHeaderL(hdr, HTTP::EUserAgent, KUserAgent);
  SetHeaderL(hdr, HTTP::EAccept, KAccept);
  SetHeaderL(hdr, HTTP::EContentType, aContentType);

  // Set this class as an data supplier. Inherited MHTTPDataSupplier methods
  // are called when framework needs to send body data.
  MHTTPDataSupplier* dataSupplier = this;
  m_iTransaction.Request().SetBody(*dataSupplier);

  // Delete previous buffer and allocate a new buffer
  if (m_pResponseBody)
  {
    delete m_pResponseBody;
    m_pResponseBody = NULL;
  }
  m_pResponseBody = HBufC8::New(HTTP_BODY_CHUNK);
  m_iStatusCode = 0;

  // Submit the transaction. After this the framework will give transaction
  // events via MHFRunL and MHFRunError.
  m_iTransaction.SubmitL();

  m_bRunning = ETrue;
  m_iHttpAttempt = 0;

  // Start timer (if required)
  TRAP_IGNORE( StartTimerL(iMaxTimer) );

  return KErrNone;
}

void CHttpModule::CancelTransaction()
{
  if(!m_bRunning)
  {
    return;
  }
  
  StopTransaction();

  // Deactivate callback (if queued)
  if (IsActive())
  {
    Cancel();
  }

  // Not running anymore
  m_bRunning = EFalse;
}

void CHttpModule::StopTransaction()
{
  if(!m_bRunning)
  {
    return;
  }
  
  // Close() also cancels transaction (Cancel() can also be used but 
  // resources allocated by transaction must be still freed with Close())
  m_iTransaction.Close();

  // Stop the timer
  StopTimer();
}

void CHttpModule::GetCookiesL(RHTTPTransaction& aTransaction)
{
  RHTTPResponse iResponse = aTransaction.Response();
  RStringPool iStringPool = aTransaction.Session().StringPool();
  
  //Check if the response header has a Cookie
  RStringF cookieField = iStringPool.StringF(HTTP::ESetCookie, RHTTPSession::GetTable());

  RHTTPHeaders respHeader = iResponse.GetHeaderCollection();
  THTTPHdrVal headerValue;

  TInt retVal = respHeader.GetField(cookieField, 0, headerValue);
  if (retVal == KErrNotFound)
  {
    // Cookie not present
    cookieField.Close();
    return;
  }
  
  if (headerValue.StrF()== iStringPool.StringF(HTTP::ECookie, RHTTPSession::GetTable()))
  {
    TInt parts = respHeader.FieldPartsL(cookieField);

    // Get all the cookies name value pairs.
    for (TInt index = 0; index < parts; index++ )
    {
      RStringF strCookieNameId = iStringPool.StringF(HTTP::ECookieName, RHTTPSession::GetTable());

      retVal = respHeader.GetParam(cookieField, strCookieNameId, headerValue, index);
      strCookieNameId.Close();

      if (retVal == KErrNotFound)
      {
        continue;
      }
      
      HBufC8* cookieNameString = NULL;
      switch (headerValue.Type())
      {
        case THTTPHdrVal::KStrFVal:
          cookieNameString = HBufC8::NewLC (headerValue.StrF().DesC().Length());
          cookieNameString->Des().Copy(headerValue.StrF().DesC());
          break;
        case THTTPHdrVal::KStrVal:
          cookieNameString = HBufC8::NewLC (headerValue.Str().DesC().Length());
          cookieNameString->Des().Copy(headerValue.Str().DesC());
          break;
        default:
          //if type of Cookie string is unknown
          break;
      }
      
      if (cookieNameString == NULL)
      {
        // Unable to get cookie name
        continue;
      }

      RStringF strCookieValueID = iStringPool.StringF (HTTP::ECookieValue, RHTTPSession::GetTable());

      // Read the COOKIE VALUE.
      retVal = respHeader.GetParam (cookieField, strCookieValueID, headerValue, index);
      strCookieValueID.Close();

      if (retVal == KErrNotFound)
      {
        CleanupStack::PopAndDestroy(cookieNameString);
        continue;
      }

      HBufC8* cookieValString = NULL;
      switch (headerValue.Type ( ) )
      {
        case THTTPHdrVal::KStrFVal:
          cookieValString = HBufC8::NewLC(headerValue.StrF().DesC().Length());
          cookieValString->Des().Copy(headerValue.StrF().DesC());
          break;
        case THTTPHdrVal::KStrVal:
          cookieValString = HBufC8::NewLC(headerValue.Str().DesC().Length());
          cookieValString->Des().Copy(headerValue.Str().DesC());
          break;
        default:
          break;
      }
      
      if (cookieValString == NULL)
      {
        // Unable to get cookie value
        CleanupStack::PopAndDestroy(cookieNameString);
        continue;
      }

      DEBUG3("Cookie = ", *cookieNameString, *cookieValString);

      m_iCookieArray.Set(*cookieNameString, *cookieValString);

      CleanupStack::PopAndDestroy(cookieValString);
      CleanupStack::PopAndDestroy(cookieNameString);
    }
  }
  
  cookieField.Close();
}

void CHttpModule::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
{
  DEBUG2("CHttpModule::MHFRunL - status = ", aEvent.iStatus);
  
  switch (aEvent.iStatus) 
  {
    case THTTPEvent::EGotResponseHeaders:
    {
      // HTTP response headers have been received.
      RHTTPResponse iResponse = aTransaction.Response();

      // Get status code and text (e.g. 200 and "OK")
      TBuf<32> statusText;
      m_iStatusCode = iResponse.StatusCode();
      statusText.Copy(iResponse.StatusText().DesC());
      
      GetCookiesL(aTransaction);

      // Save headers (if required)
      if (m_pHeaderCollection)
      {
        m_pHeaderCollection->Reset();
        m_pHeaderCollection->SetStatusCode(m_iStatusCode);

        RStringPool       iStringPool   = aTransaction.Session().StringPool();
        RHTTPHeaders      iHeaders      = iResponse.GetHeaderCollection();
        THTTPHdrFieldIter iHdrFieldIter = iHeaders.Fields();

        while(!iHdrFieldIter.AtEnd())
        {
          HBufC8* pHeaderNameBuf  = HBufC8::New(150);
          HBufC8* pHeaderValueBuf = HBufC8::New(150);
          
          RStringF iHeaderName = iStringPool.StringF(iHdrFieldIter());
          pHeaderNameBuf->Des().Copy(iHeaderName.DesC());

          THTTPHdrVal iHeaderValue;
          if (iHeaders.GetField(iHeaderName, 0, iHeaderValue) == KErrNone)
          {
            THTTPHdrVal::THTTPValType iHeaderType = iHeaderValue.Type();
            switch(iHeaderType)
            {
              case THTTPHdrVal::KTIntVal:
                pHeaderValueBuf->Des().Num(iHeaderValue.Int());
                break;
              case THTTPHdrVal::KDateVal:
              {
                TDateTime iHeaderDate = iHeaderValue.DateTime();
                _LIT8(KDateFormat,"%02d/%02d/%d %02d:%02d");
                pHeaderValueBuf->Des().Format(KDateFormat, iHeaderDate.Day()+1, iHeaderDate.Month()+1,
                                              iHeaderDate.Year(), iHeaderDate.Hour(), iHeaderDate.Minute());
                break;
              }
              case THTTPHdrVal::KStrFVal:
                pHeaderValueBuf->Des().Copy(iHeaderValue.StrF().DesC());
                break;
              default:
                // Not handled
                break;
            }
            m_pHeaderCollection->SetHeader(*pHeaderNameBuf, *pHeaderValueBuf);
          }
          
          iHeaderName.Close();

          iHdrFieldIter.operator++();
        }
        
        iStringPool.Close();
      }
      break;
    }

    case THTTPEvent::EGotResponseBodyData:
    {
      // Part (or all) of response's body data received. Use 
      // aTransaction.Response().Body()->GetNextDataPart() to get the actual body data.

      // Get the body data supplier
      MHTTPDataSupplier* body = aTransaction.Response().Body();
      TPtrC8 dataChunk;

      // GetNextDataPart() returns ETrue, if the received part is the last one.
      // Ignore indication of isLast
      body->GetNextDataPart(dataChunk);

      if (m_pResponseBody != NULL && m_pResponseBody->Size() + dataChunk.Length() > m_pResponseBody->Des().MaxSize())
      {
        TInt iNewSize = m_pResponseBody->Size() + dataChunk.Length();

        HBufC8* pNewResponseBody = m_pResponseBody->ReAllocL(iNewSize);
        m_pResponseBody = pNewResponseBody;
      }
      if (m_pResponseBody != NULL)
      {
        m_pResponseBody->Des().Append(dataChunk);
      }
      
      // Always remember to release the body data.
      body->ReleaseData();
      break;
    }

    case THTTPEvent::EResponseComplete:
    {
      // Indicates that header & body of response is completely received.
      // No further action here needed.
      break;
    }

    case THTTPEvent::ESucceeded:
    {
      DEBUG1("HTTP request succeeded");

      // Indicates that transaction succeeded. 
      // Transaction can be closed now. It's not needed anymore.
      StopTransaction();
      
      ExecuteCallback();

      break;
    }

    case THTTPEvent::EFailed:
    {
      DEBUG1("HTTP request failed");

      // Transaction completed with failure. 
      StopTransaction();

      ExecuteCallback();

      break;
    }

    case THTTPEvent::ERedirectedPermanently:
    case THTTPEvent::ERedirectedTemporarily:
    {
      if (m_iHttpAttempt > MAX_HTTP_ATTEMPTS)
      {
        DEBUG1("HTTP request failed due too many redirect");

        StopTransaction();
        
        ExecuteCallback();
      }
      else
      {
        TBuf8<150> iNewUri;
        RHTTPRequest req = aTransaction.Request();
        iNewUri.Copy(req.URI().UriDes());

        // Submit the new transaction with updated URL
        m_iTransaction.SubmitL();
        m_iHttpAttempt++;
      }
      break;
    }

    // There are more events in THTTPEvent, but they are not usually needed.
    // In any case, ESucceeded or EFailed will be sent at the end, so no need
    // to take any action now.
    default:
      // Nothing to do here
      break;
  }
}

TInt CHttpModule::MHFRunError(TInt aError, RHTTPTransaction /*aTransaction*/, const THTTPEvent& /*aEvent*/)
{
  // Just notify about the error and return KErrNone.
  DEBUG2("CHttpModule::MHFRunError - error = ", aError);

  return KErrNone;
}

TBool CHttpModule::GetNextDataPart(TPtrC8& aDataPart)
{
  if (m_pPostData) 
  {
    // Provide pointer to next chunk of data (return ETrue, if last chunk)
    // Usually only one chunk is needed, but sending big file could require
    // loading the file in small parts.
    aDataPart.Set(m_pPostData->Des());
  }
  return ETrue;
}

void CHttpModule::ReleaseData()
{
  // It's safe to delete m_pPostData now.
  if (m_pPostData)
  {
    delete m_pPostData;
    m_pPostData = NULL;
  }

  // When sending data in multiple parts we must notify the framework here:
  // (the framework can call GetNextDataPart() when we notify it by calling
  //  NotifyNewRequestBodyPartL())
  /*
  // Not needed unless we send data in multiple parts
    TRAPD(err, m_iTransaction.NotifyNewRequestBodyPartL());
    if (err != KErrNone)
    Panic(EClientEngine);
  */
}

TInt CHttpModule::Reset()
{
  // Nothing needed since m_pPostData still exists and contains all the data. 
  // (If a file is used and read in small parts we should seek to beginning 
  // of file and provide the first chunk again in GetNextDataPart() )
  return KErrNone;
}

TInt CHttpModule::OverallDataSize()
{
  if(m_pPostData)
  {
    return m_pPostData->Length();
  }
  else
  {
    return KErrNotFound ;
  }
}

TBool CHttpModule::GetCredentialsL(const TUriC8& /*aURI*/, RString aRealm, RStringF /*aAuthenticationType*/, RString& aUsername, RString& aPassword)
{
  // aURI, aReal and aAuthenticationType are informational only. We only need 
  // to set aUsername and aPassword and return ETrue, if aUsername and 
  // aPassword are provided by user.

  if (m_iHttpAttempt > MAX_HTTP_ATTEMPTS)
  {
    return EFalse;
  }

  if (m_pUsername != NULL && m_pPassword != NULL)
  {
    TRAPD(err, aUsername = aRealm.Pool().OpenStringL(*m_pUsername));
    if (err != KErrNone)
    {
      return EFalse;
    }

    TRAP(err, aPassword = aRealm.Pool().OpenStringL(*m_pPassword));
    if (err != KErrNone)
    {
      return EFalse;
    }
  }

  return ETrue;
}

TUint32 CHttpModule::ConnectionNameToIap(const TDesC8& aConnectionName)
{
  TUint32 iap = 0;

  if (aConnectionName.Length() == 0)
  {
    return iap;
  }
  
  TBuf<100> iQuery;
  iQuery.Copy(aConnectionName);
  iQuery.Insert(0, _L("SELECT * FROM IAP WHERE NAME = '"));
  iQuery.Append(_L("'"));
  
  CCommsDatabase *db;
  CCommsDbTableView *view;
  db = CCommsDatabase::NewL(EDatabaseTypeIAP);
  view = db->OpenViewLC(_L("IAP"), iQuery);
  TInt result = view->GotoFirstRecord();
  if (result == KErrNone)
  {
    view->ReadUintL(_L("Id"), iap);
  }
  else
  {
    iap = 0;
  }
  CleanupStack::PopAndDestroy(); //view 
  delete db;

  return iap;
}

void CHttpModule::StartTimerL(TInt iMaxTimer)
{
  // Stop previous timer
  StopTimer();

  if (iMaxTimer > 0)
  {
    if (m_pHttpTimer == NULL)
    {
      m_pHttpTimer = CPeriodic::NewL(CActive::EPriorityIdle);
    }
    m_pHttpTimer->Start( iMaxTimer * 1000, iMaxTimer * 1000, TCallBack(CHttpModule::HttpTimerCallBack, this) );
  }
}

void CHttpModule::StopTimer()
{
  if (m_pHttpTimer && m_pHttpTimer->IsActive())
  {
    m_pHttpTimer->Cancel();
  }
}

TInt CHttpModule::HttpTimerCallBack(TAny *aPtr)
{
  CHttpModule* pModule = (CHttpModule*)aPtr;
  pModule->DoHttpTimerCallback();
  return FALSE;
}

void CHttpModule::DoHttpTimerCallback()
{
  DEBUG1("HTTP request timeout");

  // Stop timer
  StopTimer();
  
  if (!m_bRunning)
  {
    return;
  }

  // Cancel transaction
  StopTransaction();

  if (m_pObserver)
  {
    // Sending a 408 Timeout response and blank the body
    m_iStatusCode = 408;
    if (m_pResponseBody)
    {
      delete m_pResponseBody;
      m_pResponseBody = NULL;
    }
    
    ExecuteCallback();
  }
}

void CHttpModule::ExecuteCallback()
{
  // Set active state to pending
  iStatus = KRequestPending;
  
  // Prepare for RunL
  TRequestStatus* pStatus = &iStatus;
  User::RequestComplete(pStatus, KErrNone);
  if (!IsActive())
  {
    SetActive();
  }
}

void CHttpModule::RunL()
{
  // Not running anymore
  // Set it here so we can immediately start a new HTTP request
  m_bRunning = EFalse;

  // Duplicate the body and the status code
  TInt iStatusCode = m_iStatusCode;
  HBufC8* pResBody = NULL;
  if (m_pResponseBody)
  {
    pResBody = m_pResponseBody->AllocL();
  }
  
  // Delete old response body
  if (m_pResponseBody)
  {
    delete m_pResponseBody;
    m_pResponseBody = NULL;
  }
  m_iStatusCode = 0;

  // Invoke callback
  if (m_pObserver)
  {
    if (pResBody)
    {
      m_pObserver->HttpResult(iStatusCode, *pResBody);
    }
    else
    {
      m_pObserver->HttpResult(m_iStatusCode, _L8(""));
    }
  }
  
  // delete temporary response body
  if (pResBody)
  {
    delete pResBody;
    pResBody = NULL;
  }
}

void CHttpModule::DoCancel()
{
  // In case of cancel, we can free reset the response
  if (m_pResponseBody)
  {
    delete m_pResponseBody;
    m_pResponseBody = NULL;
  }
  m_iStatusCode = 0;  

  // Not running anymore
  m_bRunning = EFalse;
}

